﻿using System;
using System.IO;
using TekaMUD.Engine.Blocks;
using System.Threading;
using TekaMUD.Engine.Framework;
using TekaMUD.Engine.IO;
using TekaMUD.Engine.Commands;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace TekaMUD.Engine
{
	[Obsolete("Needs locking. Accesed by IO threads and command queue")]
	public class StdioChannel : BaseChannel
	{
		private object SyncRoot;
		private TextReader inStream;
		private TextWriter outStream;
		private volatile bool Cursor_rebased;

		public StdioChannel(Player player, TextReader inputStream, TextWriter outStream)
		{
			Player = player;
			inStream = inputStream;
			this.outStream = outStream;
			SyncRoot = new object();
			Status = ChannelStatusEnum.Opened;
			Cursor_rebased = false;
		}

		public void ReadLoop()
		{
			WriteString(PlayerMgmtCommands.GetMOTD());

			while(Status == ChannelStatusEnum.Opened)
			{
				try
				{
					string command = inStream.ReadLine();
					
					lock (SyncRoot)
					{
						Cursor_rebased = true;
					}

					CommandQueue.BuildCommand(this, Player, command);

				}
				catch (Exception ex)
				{
					Logger.LogError("Exception in StdioChannel read loop: " + ex.Message);
				}
			}
		}

		public override void Close()
		{
			Player.Status = PlayerStatus.Offline;
			Status = ChannelStatusEnum.Closed;

			ChannelManager.CloseChannel(this);
		}

		public override void WriteString(string s)
		{
			lock (SyncRoot)
			{
				CheckCursorRebased();
				DoWrite(s); 
				
			}
		}

		public override void SendPrompt()
		{
			if (Status == ChannelStatusEnum.Opened && Player.Status == PlayerStatus.Active)
			{
				outStream.WriteLine();
				outStream.Write(Player.PlayerPrompt);
				Cursor_rebased = false;
			}
		}

		/// <summary>
		/// Effectively writes to the underlying stream. In case the output is hold, writes to a temporary buffer.
		/// </summary>
		/// <remarks>
		/// To write in a buffered manner, call channel's write methods inside a using(new BufferedOutputHolder(channel)).
		/// When disposed the output will be flushed.
		/// </remarks>
		private void DoWrite(string str)
		{
			DoWrite(str, true);
		}

		private void DoWrite(string str, bool sendPrompt)
		{
			ChannelOutputHolder coh = CurrentOutputHolder;

			if (coh == null)
			{
				outStream.Write(str);
				if(sendPrompt)
					SendPrompt();
			}
			else
				coh.Write(str);
		}

		/// <summary>
		/// Checks if the cursor has been reset to the first column.
		/// </summary>
		private void CheckCursorRebased()
		{
			if (Cursor_rebased)
				return;

			DoWrite("\r\n", false);
			Cursor_rebased = true;
		}


		public void Flush()
		{
		}

		public override void WriteLine(string s, AnsiColors fgColor, AnsiColors? bgColor, bool brightFG, bool brightBG)
		{
			throw new NotImplementedException();
		}

		public override void WriteString(string s, AnsiColors fgColor, AnsiColors? bgColor, bool brightFG, bool brightBG)
		{
			throw new NotImplementedException();
		}

		protected override void FlushHolderToStream(ChannelOutputHolder coh)
		{
			outStream.Write(coh.GetContents());
			SendPrompt();
		}

		public override string ToString()
		{
			return "Stdio channel";
		}
	}
}
